home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / wnos / wn941101 / pc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-10  |  22.0 KB  |  953 lines

  1. /* OS- and machine-dependent stuff for IBM-PC running MS-DOS and Turbo-C */
  2. #include <stdio.h>
  3. #include <conio.h>
  4. #include <dir.h>
  5. #include <dos.h>
  6. #include <io.h>
  7. #include <sys/stat.h>
  8. #include <string.h>
  9. #include <process.h>
  10. #include <fcntl.h>
  11. #include <alloc.h>
  12. #include <stdarg.h>
  13. #include <bios.h>
  14. #include "global.h"
  15. #include "config.h"
  16. #include "mbuf.h"
  17. #include "socket.h"
  18. #include "internet.h"
  19. #include "iface.h"
  20. #include "cmdparse.h"
  21. #include "pc.h"
  22. #include "proc.h"
  23. #include "session.h"
  24. #include "smtp.h"
  25. #ifdef SCC
  26. #include "scc.h"
  27. #endif
  28. #ifdef PACKET
  29. #include "pktdrvr.h"
  30. #endif
  31. #ifdef ASY
  32. #include "asy.h"
  33. #include "8250.h"
  34. #endif
  35. #include "domain.h"
  36.  
  37. #define    DEL        0x7f
  38.  
  39. static int near kbchar __ARGS((void));
  40.  
  41. extern struct proc *Display;
  42. extern struct timer Statustimer;
  43.  
  44. int Tick;
  45. static int32 Starttime;
  46. int32 Clock;
  47.  
  48. /* This flag is set by setirq() if IRQ 8-15 is used, indicating
  49.  * that the machine is a PC/AT with a second 8259 interrupt controller.
  50.  * If this flag is set, the interrupt return code in pcgen.asm will
  51.  * send an End of Interrupt command to the second 8259 as well as the
  52.  * first.
  53.  */
  54. int Isat = 0;
  55.  
  56. static char Tsbuf[BUFSIZ];
  57. static int saved_break;
  58.  
  59. #define KBSIZE    256        /* Keyboard input buffer */
  60.  
  61. static struct {
  62.     char buf[KBSIZE];
  63.     char *wp;
  64.     char *rp;
  65.     int cnt;
  66. } Keyboard;
  67.  
  68. static int Swap = 0;
  69. static long near bioscnt __ARGS((void));
  70. static int near _spawn __ARGS((int mode,char *env,char *def,int argc,char *argv[]));
  71. extern int do_spawn __ARGS((int swapping,char *execfname,char *cmdtail,unsigned envlen,char *envp));
  72. extern int prep_swap __ARGS((unsigned method,char *swapfname));
  73.  
  74. /* Directly read BIOS count of time ticks. This is used instead of
  75.  * calling biostime(0,0L). The latter calls BIOS INT 1A, AH=0,
  76.  * which resets the midnight overflow flag, losing days on the clock.
  77.  */
  78. static long near
  79. bioscnt()
  80. {
  81.     int i_state = dirps();
  82.     long rval = *(long far *)MK_FP(0x40,0x6c);
  83.     restore(i_state);
  84.     return rval;
  85. }
  86.  
  87. #ifdef MSDOS
  88. /*
  89.  * define the error messages for trapping disk problems - D.Crompton
  90.  * ported into WNOS DB3FL.910407
  91.  */
  92. static int
  93. errhandler(int errval,int ax,int bp,int si)
  94. {
  95.     char *crit_err_msg[] = {
  96.         "write protect",
  97.         "unknown unit",
  98.         "not ready",
  99.         "unknown command",
  100.         "data error (CRC)",
  101.         "bad request",
  102.         "seek error",
  103.         "unknown media type",
  104.         "sector not found",
  105.         "printer out of paper",
  106.         "write fault",
  107.         "read fault",
  108.         "general failure",
  109.         "reserved",
  110.         "reserved",
  111.         "invalid disk change"
  112.     };
  113.     char msg[80];
  114.     int drive, errorno;
  115.     unsigned di = _DI;
  116.  
  117.     if (ax < 0) {
  118.         hardretn(3);
  119.         return 3;
  120.     }
  121.     drive = ax & 0x00FF;
  122.     errorno = di & 0x00FF;
  123.     sprintf(msg,"\n\rError: %s on drive %c\n\r$",
  124.         crit_err_msg[errorno], 'A' + drive);
  125.     bdosptr(0x09,msg,0);
  126.     hardretn(3);
  127.     return 3;
  128. }
  129. #else
  130. static int
  131. errhandler(errval,ax,bp,si)
  132. int errval,ax,bp,si;
  133. {
  134.     return 3;    /* Fail the system call */
  135. }
  136. #endif /* MSDOS */
  137.  
  138. /* Called at startup time to set up console I/O, memory heap */
  139. void
  140. ioinit()
  141. {
  142.     extern int getproc __ARGS((void));
  143.  
  144.     /* Fail all I/O errors */
  145.     harderr(errhandler);
  146.  
  147.     /* Save these two file table entries for something more useful */
  148.     fclose(stdaux);
  149.     fclose(stdprn);
  150.     setbuf(stdout,Tsbuf);
  151.  
  152.     /* this breaks tab expansion so you must use ANSI or NANSI */
  153.     ioctl(fileno(stdout), 1, (ioctl(fileno(stdout),0) & 0xff) | 0x20);
  154.     saved_break = getcbrk();
  155.     setcbrk(0);
  156.  
  157.     Starttime = bioscnt();
  158.     /* Link timer handler into timer interrupt chain */
  159.     chtimer(btick);
  160.  
  161.     /* Find out what multitasker we're running under, if any */
  162.     chktasker();
  163.  
  164.     Isat = (getproc() > 5);
  165.  
  166.     /* Initialize keyboard queue */
  167.     Keyboard.rp = Keyboard.wp = Keyboard.buf;
  168.  
  169. }
  170. /* Called just before exiting to restore console state */
  171. void
  172. iostop()
  173. {
  174.     struct iface *ifp, *iftmp = 0;
  175.  
  176.     ioctl(fileno(stdout), 1, (ioctl(fileno(stdout), 0) & 0xff) & ~0x20);
  177.     setcbrk(saved_break);
  178.  
  179.     for(ifp = Ifaces;ifp != NULLIF;ifp = iftmp){
  180.         iftmp = ifp->next;
  181.         if_detach(ifp);
  182.     }
  183. #ifdef SCC
  184.     sccstop();    /* reset int mask for all scc boards */
  185. #endif
  186.     /* Unlink timer handler from timer chain */
  187.     uchtimer();
  188. }
  189.  
  190. /*-----------------------------------------------------------------------*/
  191. typedef struct   {
  192.    struct text_info tr;
  193.    char *sbuf;
  194. }Doslock;
  195.  
  196. static unsigned near dos_prepare(Doslock *dl);
  197. static void near dos_restore(Doslock *dl);
  198. /* static unsigned near getmaxfree(void); */
  199.  
  200. static int do_exec __ARGS((char *xfn,char *pars,int spawn,unsigned needed));
  201.  
  202. /* Return codes (only upper byte significant) */
  203.  
  204. #define RC_PREPERR   0x0100
  205. #define RC_NOFILE    0x0200
  206. #define RC_EXECERR   0x0300
  207. #define RC_ENVERR    0x0400
  208. #define RC_SWAPERR   0x0500
  209.  
  210. /* Swap method and option flags */
  211.  
  212. #define USE_EMS      0x01
  213. #define USE_XMS      0x02
  214. #define USE_FILE     0x04
  215. #define EMS_FIRST    0x00
  216. #define XMS_FIRST    0x10
  217. #define HIDE_FILE    0x40
  218. #define NO_PREALLOC  0x100
  219. #define CHECK_NET    0x200
  220.  
  221.  
  222.  
  223. #define USE_ALL      (USE_EMS | USE_XMS | USE_FILE)
  224.  
  225.  
  226.  
  227. static int dexists (char *filename)
  228. {
  229. struct stat stbuf;
  230.    return (stat (filename, &stbuf) != -1) ? 1 : 0;
  231. }
  232.  
  233. static int near
  234. _spawn(int mode,char *env,char *def,int argc,char *argv[])
  235. {
  236. Doslock dl;
  237. int ret = 0;
  238. char *command, *p;
  239.  
  240.    if((p = getenv(env)) == NULLCHAR)
  241.       p = def;
  242.  
  243.    dos_prepare(&dl);
  244.  
  245.    if (!Swap || Mtasker)   {
  246.       if (argc < 2)
  247.          system(p);
  248.       else
  249.          ret = spawnvp(P_WAIT,argv[1],argv + 1);
  250.    } else {
  251.       if (argc > 1)   {
  252.          if((command = mxallocw(256)) != NULLCHAR) {
  253.             int i;
  254.             strcat(command,"/c ");
  255.             for(i = 1; i < argc; i++) {
  256.                 strcat(command,argv[i]);
  257.                 strcat(command," ");
  258.             }
  259.             do_exec (p, command, USE_ALL, 0xffff);
  260.             xfree (command);
  261.          }
  262.       } else
  263.          do_exec (p, "", USE_ALL, 0xffff);
  264.    }
  265.  
  266.    dos_restore(&dl);
  267.  
  268.    return ret;
  269. }
  270.  
  271. /*----------------------------------------------------------------------*
  272. *-----------------------------------------------------------------------*/
  273. int dobmail(argc,argv,p)
  274. int argc;
  275. char *argv[];
  276. void *p;
  277. {
  278. int ret;
  279.  
  280.    ret = _spawn(1,"MAILER","BM.EXE",argc,argv);
  281.    /*-------------------------------------------------------------------*
  282.    * process Mailprompts                                                *
  283.    *--------------------------------------------------------------------*/
  284.    smtptick(NULL);                      /* tickle smtp to send any mail */
  285.    return ret;
  286. }
  287.  
  288.  #ifdef XXX 
  289. /*----------------------------------------------------------------------*
  290. * Spawn dg4dam's NNVIEW as subshell                                     *
  291. *-----------------------------------------------------------------------*/
  292. int donntpview(argc,argv,p)
  293. int argc;
  294. char *argv[];
  295. void *p;
  296. {
  297.  
  298.    return (_spawn(1,"NNTPVIEW","NNTPVIEW.EXE",argc,argv));
  299.  
  300. }
  301.  #endif 
  302.  
  303. int doshell(argc,argv,p)
  304. int argc;
  305. char *argv[];
  306. void *p;
  307. {
  308.    return _spawn(1,"COMSPEC","COMMAND.COM",argc,argv);
  309.    /*-------------------------------------------------------------------*
  310.    * .... spawn the subshell                                            *
  311.    *--------------------------------------------------------------------*/
  312. /*
  313.    if(argc == 1 || !stricmp(argv[1], "/c")) {
  314.       return _spawn(1,0,0,argv);
  315.    } else
  316.       return _spawn(1,0,0,argv);
  317. */
  318. }
  319.  
  320. /*----------------------------------------------------------------------*
  321. *-----------------------------------------------------------------------*/
  322.  
  323. #define SWAP_FILENAME "$$AAAAAA.AAA"
  324.  
  325. /* internal flags for prep_swap */
  326.  
  327. #define CREAT_TEMP      0x0080
  328. #define DONT_SWAP_ENV   0x4000
  329.  
  330. static int do_exec (char *exfn, char *epars, int spwn, unsigned needed)
  331. {
  332. static char swapfn [82];
  333. static char execfn [82];
  334. unsigned avail;
  335. union REGS regs;
  336. int rc, idx, swapping;
  337.  
  338.    strcpy (execfn, exfn);
  339.  
  340.    if (!spwn)
  341.       swapping = -1;
  342.    else {
  343.  
  344.       /*----------------------------------------------------------------*
  345.       * Determine amount of free memory                                 *
  346.       *-----------------------------------------------------------------*/
  347.       regs.x.ax = 0x4800;
  348.       regs.x.bx = 0xffff;
  349.       intdos (®s, ®s);
  350.       avail = regs.x.bx;
  351.  
  352.       /*----------------------------------------------------------------*
  353.       * No swapping if available memory > needed                        *
  354.       *-----------------------------------------------------------------*/
  355.       if (needed < avail)
  356.          swapping = 0;
  357.       else {
  358.          /* Swapping necessary, use 'TMP' or 'TEMP' environment variable
  359.            to determine swap file path if defined. */
  360.  
  361.          swapping = spwn;
  362.          if (spwn & USE_FILE) {
  363.             char *temp = getenv("TEMP");
  364.             strcpy (swapfn,(temp != NULLCHAR) ? temp : "");
  365.  
  366.             if (_osmajor >= 3)
  367.                swapping |= CREAT_TEMP;
  368.             else {
  369.                strcat (swapfn, SWAP_FILENAME);
  370.                idx = strlen (swapfn) - 1;
  371.                while (dexists (swapfn)) {
  372.                   if (swapfn[idx] == 'Z')
  373.                      idx--;
  374.                   if (swapfn[idx] == '.')
  375.                      idx--;
  376.                   swapfn[idx]++;
  377.                }
  378.             }
  379.          }
  380.       }
  381.    }
  382.  
  383.    /* All set up, ready to go. */
  384.  
  385.    if (swapping > 0) {
  386.       swapping |= DONT_SWAP_ENV;
  387.  
  388.       rc = prep_swap (swapping, swapfn);
  389.       if (rc < 0)
  390.          return RC_PREPERR | -rc;
  391.    }
  392.  
  393.    rc = do_spawn (swapping, execfn, epars, 0,0);
  394.  
  395.    return rc;
  396. }
  397.  
  398. static unsigned near
  399. dos_prepare(Doslock *dl)
  400. {
  401.    /*-------------------------------------------------------------------*
  402.    *  save the current screen layout                                    *
  403.    *--------------------------------------------------------------------*/
  404.    gettextinfo(&dl->tr);
  405.  
  406.    if ((dl->sbuf = mxallocw(2*dl->tr.screenheight*dl->tr.screenwidth))==0)
  407.       return(0);
  408.  
  409.    gettext(dl->tr.winleft, dl->tr.wintop,
  410.            dl->tr.winright, dl->tr.winbottom,
  411.            dl->sbuf);
  412.  
  413.    /*-------------------------------------------------------------------*
  414.    * temporarily suspend all our irq's                                  *
  415.    * SEE THE CHANGES IN THE PARTICULAR xxx_init() and xxx_stop rtns.    *
  416.    * dk5dc                                                              *
  417.    *--------------------------------------------------------------------*/
  418.    if (Swap)   {
  419. #ifdef ASY
  420.       int i;
  421.       struct asy *asyp;
  422.  
  423.       for(i=0;i < ASY_MAX;i++){         /* scan the asy structures      */
  424.          asyp = &Asy[i];
  425.          if(asyp->iface == NULLIF)
  426.             continue;
  427.          asy_stop(asyp->iface,1);       /* note:changes in 8250.c dk5dc */
  428.       }
  429. #endif
  430. #ifdef SCC
  431.       sccstop();                        /* brute force !                */
  432. #endif
  433. #ifdef PACKET
  434.       pkt_suspend();                    /* see pktdrvr.c                */
  435. #endif
  436.    }
  437.    stop_timer(&Statustimer);
  438.    uchtimer();                         /* disconnect the timer interrupt*/
  439.    return(1);
  440. }
  441.  
  442. /*----------------------------------------------------------------------*
  443. *-----------------------------------------------------------------------*/
  444. static void near dos_restore(Doslock *dl)
  445. {
  446. #ifdef PACKET
  447. extern INTERRUPT (*Pkvec[])();
  448. #endif
  449.  
  450.    /*-------------------------------------------------------------------*
  451.    * restore the screen layout                                          *
  452.    *--------------------------------------------------------------------*/
  453.    puttext(dl->tr.winleft, dl->tr.wintop,
  454.            dl->tr.winright, dl->tr.winbottom,
  455.            dl->sbuf);
  456.    gotoxy(dl->tr.curx,dl->tr.cury);
  457.    xfree(dl->sbuf);
  458.  
  459.    /*-------------------------------------------------------------------*
  460.    * restore our irq's                                                  *
  461.    * SEE THE CHANGES IN THE PARTICULAR xxx_init() and xxx_stop() rtns.  *
  462.    * dk5dc                                                              *
  463.    *--------------------------------------------------------------------*/
  464.    if (Swap)   {
  465. #ifdef ASY
  466.       int i;
  467.       struct asy *asyp;
  468.  
  469.       for(i=0;i < ASY_MAX;i++){
  470.          asyp = &Asy[i];
  471.          if(asyp->iface == NULLIF)
  472.             continue;
  473.          asy_init(i,asyp->iface,0,0,0,0,0);
  474.          asy_speed(i,asyp->speed);
  475.       }
  476. #endif
  477. #ifdef SCC
  478.       sccreact();                       /* new function in scc.c dk5dc  */
  479. #endif
  480. #ifdef PACKET
  481.       pkt_restore();                    /* see pktdrvr.c*/
  482. #endif
  483.    }
  484.    chtimer(btick);                      /* rechain the timer interrupt  */
  485.    start_timer(&Statustimer);
  486. }
  487.  
  488. doswap(int argc,char *argv[],void *p)
  489. {
  490.    return setbool(&Swap,"EMS/XMS/FILE swapping",argc,argv);
  491. }
  492.  
  493. /* Keyboard interrupt handler */
  494. void
  495. kbint()
  496. {
  497.     int c, sig = 0;
  498.  
  499.     while((c = kbraw()) != -1 && Keyboard.cnt < KBSIZE){
  500.         sig = 1;
  501.         *Keyboard.wp++ = c;
  502.         if(Keyboard.wp == &Keyboard.buf[KBSIZE])
  503.             Keyboard.wp = Keyboard.buf;
  504.         Keyboard.cnt++;
  505.     }
  506.     if(sig){
  507.         psignal(&Keyboard,0);
  508.     }
  509. }
  510.  
  511. static int near
  512. kbchar()
  513. {
  514.     unsigned char c;
  515.     int i_state = dirps();
  516.  
  517.     while(Keyboard.cnt == 0)
  518.         pwait(&Keyboard);
  519.     Keyboard.cnt--;
  520.     restore(i_state);
  521.     c = *Keyboard.rp++;
  522.     if(Keyboard.rp == &Keyboard.buf[KBSIZE])
  523.         Keyboard.rp = Keyboard.buf;
  524.     return c;
  525. }
  526.  
  527. /* Read characters from the keyboard, translating them to "real" ASCII.
  528.  * If none are ready, block. The F-10 key is special; translate it to -2.
  529.  */
  530. int
  531. kbread()
  532. {
  533.     int c;
  534.  
  535.     if((c = kbchar()) == 0){
  536.         /* Lead-in to a special char */
  537.         switch(c = kbchar()){
  538.         case 3:                            /* NULL (bizzare!) */
  539.             c = 0;
  540.             break;
  541.         case 83:                        /* DEL key */
  542.             c = 0x7f;
  543.             break;
  544.         case 68:                        /* F10 - used as command escape */
  545.             c = -2;
  546.             break;
  547.         case 67:                        /* F9 temporarily used */
  548.         case 0x71:                        /* ALT-F10 - used as trace screen */
  549.             c = -13;
  550.             break;
  551.         case 80:                          /* down */
  552.             c = 0x10;
  553.             break;
  554.         case 72:                        /* up */
  555.             c = 0x0f;
  556.             break;
  557.         default:
  558.             if(c > 58 && c < 67)        /* F1 to F8 */
  559.                 c = (c - 56) * -1;
  560.             else                        /* Dunno what it is */
  561.                 c = -1;
  562.         }
  563.     }
  564.     return c;
  565. }
  566.  
  567. /* Install hardware interrupt handler.
  568.  * Takes IRQ numbers from 0-7 (0-15 on AT) and maps to actual 8086/286 vectors
  569.  * Note that bus line IRQ2 maps to IRQ9 on the AT
  570.  */
  571. int
  572. setirq(irq,handler)
  573. unsigned irq;
  574. INTERRUPT (*handler)();
  575. {
  576.     /* Set interrupt vector */
  577.     if(irq < 8){
  578.         setvect(8+irq,handler);
  579.     } else if(irq < 16){
  580.         Isat = 1;
  581.         setvect(0x70 + irq - 8,handler);
  582.     } else {
  583.         return -1;
  584.     }
  585.     return 0;
  586. }
  587.  
  588. /* Return pointer to hardware interrupt handler.
  589.  * Takes IRQ numbers from 0-7 (0-15 on AT) and maps to actual 8086/286 vectors
  590.  */
  591. INTERRUPT
  592. (*getirq(irq))()
  593. unsigned int irq;
  594. {
  595.     /* Set interrupt vector */
  596.     if(irq < 8){
  597.         return getvect(8+irq);
  598.     } else if(irq < 16){
  599.         return getvect(0x70 + irq - 8);
  600.     } else {
  601.         return NULLVIFP;
  602.     }
  603. }
  604.  
  605. /* Disable hardware interrupt */
  606. int
  607. maskoff(irq)
  608. unsigned irq;
  609. {
  610.     if(irq < 8){
  611.         setbit(0x21,(char)(1<<irq));
  612.     } else if(irq < 16){
  613.         irq -= 8;
  614.         setbit(0xa1,(char)(1<<irq));
  615.     } else {
  616.         return -1;
  617.     }
  618.     return 0;
  619. }
  620.  
  621. /* Enable hardware interrupt */
  622. int
  623. maskon(irq)
  624. unsigned irq;
  625.  {
  626.     if(irq < 8){
  627.         clrbit(0x21,(char)(1<<irq));
  628.     } else if(irq < 16){
  629.         irq -= 8;
  630.         clrbit(0xa1,(char)(1<<irq));
  631.     } else {
  632.         return -1;
  633.     }
  634.     return 0;
  635. }
  636.  
  637. /* Return 1 if specified interrupt is enabled, 0 if not, -1 if invalid */
  638. int
  639. getmask(irq)
  640. unsigned irq;
  641. {
  642.     if(irq < 8)
  643.         return (inportb(0x21) & (1 << irq)) ? 0 : 1;
  644.     else if(irq < 16){
  645.         irq -= 8;
  646.         return (inportb(0xa1) & (1 << irq)) ? 0 : 1;
  647.     } else
  648.         return -1;
  649. }
  650.  
  651. /* Called from assembler stub linked to BIOS interrupt 1C, called on each
  652.  * hardware clock tick. Signal a clock tick to the timer process.
  653.  */
  654. void
  655. ctick()
  656. {
  657.     Tick++;
  658.     psignal(&Tick,1);
  659. }
  660.  
  661. /* Called from the timer process on every tick. NOTE! This function
  662.  * can NOT be called at interrupt time because it calls the BIOS
  663.  */
  664. void
  665. pctick()
  666. {
  667.     static long oldt;    /* Value of bioscnt() on last call */
  668.     static long days;    /* # of times bioscnt() has rolled over */
  669.  
  670.     /* Update the time-since-boot */
  671.     long t = bioscnt();
  672.  
  673.     if(t < oldt)
  674.         days++;    /* bioscnt has rolled past midnight */
  675.     oldt = t;
  676.     Clock = (days * 0x1800b0L) + t - Starttime;
  677. }
  678.  
  679. /* Set bit(s) in I/O port */
  680. void
  681. setbit(port,bits)
  682. unsigned port;
  683. char bits;
  684. {
  685.     outportb(port,(char)inportb(port)|bits);
  686. }
  687.  
  688. /* Clear bit(s) in I/O port */
  689. void
  690. clrbit(port,bits)
  691. unsigned port;
  692. char bits;
  693. {
  694.     outportb(port,(char)(inportb(port) & ~bits));
  695. }
  696.  
  697. /* Set or clear selected bits(s) in I/O port */
  698. void
  699. writebit(port,mask,val)
  700. unsigned port;
  701. char mask;
  702. int val;
  703. {
  704.     char x = inportb(port);
  705.  
  706.     if(val)
  707.         x |= mask;
  708.     else
  709.         x &= ~mask;
  710.  
  711.     outportb(port,x);
  712. }
  713.  
  714. /* Convert a pointer to a long integer */
  715. long
  716. ptol(p)
  717. void *p;
  718. {
  719.     long x = FP_OFF(p);
  720.  
  721. #ifdef    LARGEDATA
  722.     x |= (long)FP_SEG(p) << 16;
  723. #endif
  724.     return x;
  725. }
  726. void *
  727. ltop(l)
  728. long l;
  729. {
  730.     unsigned seg = (unsigned)(l >> 16);
  731.     unsigned offset = (unsigned)l;
  732.  
  733.     return MK_FP(seg,offset);
  734. }
  735. void
  736. sysreset()
  737. {
  738.     void (*foo) __ARGS((void));
  739.  
  740.     foo = MK_FP(0xffff,0);    /* FFFF:0000 is hardware reset vector */
  741.     (*foo)();
  742. }
  743. void
  744. newscreen(sp)
  745. struct session *sp;
  746. {
  747.     if(sp != NULLSESSION)
  748.         sp->screen = mxallocw(sizeof(struct screen));
  749. }
  750. void
  751. freescreen(sp)
  752. struct session *sp;
  753. {
  754.     if(sp == NULLSESSION || sp->screen == NULLSCREEN)
  755.         return;
  756.     if(sp->screen->save != NULLCHAR)
  757.         xfree(sp->screen->save);
  758.     xfree((char *)sp->screen);
  759.     sp->screen = NULLSCREEN;    /* finish the job */
  760. }
  761.  
  762. /* Reallocate screen buffers */
  763. static void near
  764. realloc_screen(int size)
  765. {
  766. int i;
  767. char *osave, *newsave;
  768. struct session *sp;
  769.  
  770.    for(i = 0, sp = Sessions; i < Nsessions; sp++, i++)
  771.       if(sp->type != FREE)   {
  772.          if(sp->screen->save != 0)   {
  773.             newsave = mxallocw(size);
  774.             if (FP_SEG(newsave) < FP_SEG(sp->screen->save))   {
  775.                memcpy(newsave,sp->screen->save,size);
  776.                osave = sp->screen->save;
  777.                sp->screen->save = newsave;
  778.                xfree(osave);
  779.             } else
  780.                xfree(newsave);
  781.          }
  782.       }
  783. }
  784.  
  785. /* Save specified session screen and resume console screen */
  786. void
  787. swapscreen(old,new)
  788. struct session *old,*new;
  789. {
  790.     int size;
  791.     struct text_info tr;
  792.  
  793.     if(old == new)
  794.         return;    /* Nothing to do */
  795.  
  796.     gettextinfo(&tr);
  797.     size = 2 * tr.screenheight * tr.screenwidth;
  798.     if(old != NULLSESSION){
  799.         /* Save old screen */
  800.         if(old->screen->save == NULLCHAR)
  801.             old->screen->save = mxallocw(size);
  802.         if(old->screen->save != NULLCHAR){
  803.             if(old->split){
  804.                 window(1,3,80,Nrows);
  805.                 tr.winbottom = Nrows;
  806.             }
  807.             gettext(tr.winleft,tr.wintop,tr.winright,
  808.                 tr.winbottom,old->screen->save);
  809.         }
  810.         old->screen->row = tr.cury;
  811.         old->screen->col = tr.curx;
  812.     }
  813.     if(new != NULLSESSION){
  814.         /* Load new screen */
  815.         if(new->screen->save != NULLCHAR){
  816.             if(new->split)
  817.                 window(1,3,80,Nrows-2);
  818.             else {
  819.                 window(1,3,80,Nrows);
  820.                 tr.winbottom = Nrows;
  821.             }
  822.             clrscr();
  823.             puttext(tr.winleft,tr.wintop,tr.winright,
  824.                 tr.winbottom,new->screen->save);
  825.             gotoxy(new->screen->col,new->screen->row);
  826.             /* Free the memory (saves 4K on a continuous basis) */
  827.             xfree(new->screen->save);
  828.             new->screen->save = NULLCHAR;
  829.         } else {
  830.             clrscr();    /* Start with a fresh slate */
  831.             if(new->split){
  832.                 new->tsavex = new->bsavex = 1;
  833.                 new->tsavey = 2;
  834.                 new->bsavey = 24;
  835.                 window(1,Nrows-1,80,Nrows);
  836.                 cputs("_\b");
  837.                 window(1,3,80,Nrows-2);
  838.             }
  839.         }
  840.     }
  841.     realloc_screen(size);
  842.     alert(Display,(void *)1);    /* Wake him up */
  843. }
  844.  
  845. void
  846. display(int i,void *v1,void *v2)
  847. {
  848.     /* This is very tricky code. Because the value of "Current" can
  849.      * change any time we do a pwait, we have to be careful to detect
  850.      * any change and go back and start again.
  851.      */
  852.     for(;;){
  853.         int c;
  854.         struct session *sp = Current;
  855.  
  856.         if(sp->morewait) {
  857.             pwait(&sp->row);
  858.             if(sp != Current || sp->row <= 0) {
  859.                 /* Current changed value, or the user
  860.                  * hasn't really hit a key
  861.                  */
  862.                 continue;
  863.             }
  864.             /* Erase the prompt */
  865.             cputs("\r         \r");
  866.         }
  867.         sp->morewait = 0;
  868.  
  869.         if((c = rrecvchar(sp->output)) == -1){
  870.             /* the alert() in swapscreen will cause this to
  871.              * return -1 when current changes
  872.              */
  873.             pwait(NULL);    /* Prevent a nasty loop */
  874.             continue;
  875.         }
  876.         if(sp != Command) {
  877.             textattr(WHITE);
  878.         }
  879.         putch(c);
  880.  
  881.         textattr(LIGHTGRAY);
  882.  
  883.         if(sp->record != NULLFILE && c != '\r') {
  884.             fputc(c,sp->record);
  885.         }
  886.         if(sp->flowmode && c == '\n' && --sp->row <= 0) {
  887.             cputs("--More--");
  888.             sp->morewait = 1;
  889.         }
  890.     }
  891. }
  892.  
  893.  
  894. /* Return time since startup in milliseconds. If the system has an
  895.  * 8254 clock chip (standard on ATs and up) then resolution is improved
  896.  * below 55 ms (the clock tick interval) by reading back the instantaneous
  897.  * value of the counter and combining it with the global clock tick counter.
  898.  * Otherwise 55 ms resolution is provided.
  899.  *
  900.  * Reading the 8254 is a bit tricky since a tick could occur asynchronously
  901.  * between the two reads. The tick counter is examined before and after the
  902.  * hardware counter is read. If the tick counter changes, try again.
  903.  * Note: the hardware counter counts down from 65536.
  904.  */
  905. int32
  906. msclock()
  907. {
  908.     int32 hi;
  909.     int16 lo, count[4];        /* extended (48-bit) counter of timer clocks */
  910.  
  911.     if(!Isat)
  912.         return Clock * MSPTICK;
  913.  
  914.     do {
  915.         hi = Clock + Tick;
  916.         lo = clockbits();
  917.     } while(hi != Clock + Tick);
  918.  
  919.     count[0] = 0;
  920.     count[1] = hi >> 16;
  921.     count[2] = hi;
  922.     count[3] = -lo;
  923.     longmul(11,4,count);    /* The ratio 11/13125 is exact */
  924.     longdiv(13125,4,count);
  925.     return ((long)count[2] << 16) + count[3];
  926. }
  927.  
  928. /* Return clock in seconds */
  929. int32
  930. secclock()
  931. {
  932.     int32 hi;
  933.     int16 lo, count[4];        /* extended (48-bit) counter of timer clocks */
  934.  
  935.     if(!Isat)
  936.         return (Clock * MSPTICK) / 1000L;
  937.  
  938.     do {
  939.         hi = Clock + Tick;
  940.         lo = clockbits();
  941.     } while(hi != Clock + Tick);
  942.  
  943.     count[0] = 0;
  944.     count[1] = hi >> 16;
  945.     count[2] = hi;
  946.     count[3] = -lo;
  947.     longmul(11,4,count);    /* The ratio 11/13125 is exact */
  948.     longdiv(13125,4,count);
  949.     longdiv(1000,4,count);    /* Convert to seconds */
  950.     return ((long)count[2] << 16) + count[3];
  951. }
  952.  
  953.